package ru.yandex.api.money.service;

import org.json.JSONException;
import org.json.JSONObject;

import ru.yandex.api.money.model.*;
import ru.yandex.api.money.util.RequestBuilder;

/**
 * @author: Melnikov Ivan melnikov.ivan@gmail.com
 */
public class YandexMoneyService {

	private static final String API = "/api/";

	private static final String METHOD_ERROR = "error";
	
	private static final String PAYMENT_STATUS  = "status";
	private static final String PAYMENT_SUCCESS = "success";
	private static final String PAYMENT_REFUSED = "refused";
	
	private static final String REQUEST_ID = "request_id";
	private static final String REQUEST_CONTRACT = "contract";
	private static final String PAYMENT_ID = "payment_id";

	private String serviceHost = "https://money.yandex.ru"+API;
	
	public AccountInfo accountInfo(String accessToken) {
		String content = new RequestBuilder(serviceHost + "account-info")
					.auth(accessToken)
					.addParam("fake", "")
					.build();
		
		try {
			JSONObject json = new JSONObject(content);
			return new AccountInfo(json);
		} catch (JSONException e) {
			e.printStackTrace();
			return null;
		}
	}
	
	public History operationHistory(String accessToken, int start, int size) throws ApiMethodException {
		String content = new RequestBuilder(serviceHost + "operation-history")
			.auth(accessToken)
			.addParam("type", "payment deposition")
			.addParam("start_record", start)
			.addParam("records", size)
			.build();
		
		try {
			JSONObject json = new JSONObject(content);
			if (json.has(METHOD_ERROR) && !json.getString(METHOD_ERROR).isEmpty())
				throw new ApiMethodException(json.getString(METHOD_ERROR));
			
			return new History(json);
		} catch (JSONException e) {
			e.printStackTrace();
			return null;
		}
	}
	
	public Operation operationDetails(String accessToken, String operationId) throws ApiMethodException {
		String content = new RequestBuilder(serviceHost + "operation-details")
			.auth(accessToken)
			.addParam("operation_id", operationId)
			.build();
		
		try {
			JSONObject json = new JSONObject(content);
			if (json.has(METHOD_ERROR))
				throw new ApiMethodException("Illegal operation id");
			
			return new Operation(json);
		} catch (JSONException e) {
			e.printStackTrace();
			return null;
		}
	}
	
	public PaymentRequest requestPayment(String accessToken, String patternId, PaymentParam...params) throws ApiMethodException {
		RequestBuilder request = new RequestBuilder(serviceHost + "request-payment")
			.auth(accessToken)
			.addParam("pattern_id", patternId);

		for(PaymentParam param : params)
			request.addParam(param.getName(), param.getValue().toString());

		String content = request.build();
		
		try {
			JSONObject json = new JSONObject(content);
			String status = json.getString(PAYMENT_STATUS);
			if (PAYMENT_SUCCESS.equals(status)) {
				String id = json.getString(REQUEST_ID);
				String contract = json.getString(REQUEST_CONTRACT);
				return new PaymentRequest(id, contract);
			} else if (PAYMENT_REFUSED.equals(status)) {
				String msg = json.getString("error_description");
				throw new ApiMethodException(msg);
			} else 
				throw new IllegalStateException("Unknown status parameter: "+status);
			
		} catch (JSONException e) {
			e.printStackTrace();
			return null;
		}
	}
	
	public PaymentStatus processPayment(String accessToken, PaymentRequest request) throws ApiMethodException {
		String requestId = request.getId();
		return processPayment(accessToken, requestId);
	}

	public PaymentStatus processPayment(String accessToken, String requestId) throws ApiMethodException {
		String content = new RequestBuilder(serviceHost + "process-payment")
			.auth(accessToken)
			.addParam("request_id", requestId)
			.build();
		
		try {
			JSONObject json = new JSONObject(content);
			String status = json.getString(PAYMENT_STATUS);
			if (PAYMENT_SUCCESS.equals(status)) {
				String id = json.getString(PAYMENT_ID);
				return new PaymentStatus(id);
			} else if (PAYMENT_REFUSED.equals(status)) {
				String error = json.getString("error");
				String msg = getPaymentErrorMessage(error);
				throw new ApiMethodException(msg);
			} else 
				throw new IllegalStateException("Unknown status parameter: "+status);
			
		} catch (JSONException e) {
			e.printStackTrace();
			return null;
		}
	}

	private static String getPaymentErrorMessage(String error) {
		String msg;
		if ("contract_not_found".equals(error))
			msg = "Contract not found";
		else if ("not_enough_funds".equals(error))
			msg = "Not enough funds";
		else if ("limit_exceeded".equals(error))
			msg = "Limit exceeded";
		else 
			msg = error;
		return msg;
	}

	public void setServiceHost(String serviceHost) {
		this.serviceHost = serviceHost + API;
	}
	
}
